import java.awt.*;
import javax.media.j3d.*;
import javax.vecmath.*;

public class Polygon extends PhysicsObject {
	private float[] vertices;
	
	public float width;
	private float ratio;
	private Vector2f[] vertexCache;
	private Vector2f[] normalCache;
	
	public Polygon(int sides, float mass, float positionX, float positionY, 
			float velocityX, float velocityY, float orientation, 
			float angularVelocity, float extwidth, float ratio, Color3f color) {
		super(mass, positionX, positionY, velocityX, velocityY, orientation, angularVelocity);
		
		if (extwidth*ratio <= 0  || sides < 3)
			throw new IllegalArgumentException();
		
		this.ratio = ratio;
		
		//calculate vertices positions of polygon with 
		//	given number of sides centered around origin
		vertices = new float[sides*2];
		float r = extwidth*ratio/2;//width/2;
		double pi = Math.PI;
		for (int i = 0; i < sides*2; i+=2) {
			float scale = (float)Math.random();
			if(scale < 0.5f)
				scale = 0.5f;
			vertices[i] = (float) (scale * r * Math.cos(pi*i/sides));
			vertices[i+1] = (float) (scale * r * Math.sin(pi*i/sides));
		}
		
		centerOfMass.x = centerOfMass.y = 0;
		//momentOfInertia = (float)(Math.pow(width, 4) / 18); //only for triangles
		momentOfInertia = (0.5f)*(mass * r * r);//1;
		//System.out.println("mass: " + mass + "\nr: " + r);
		//System.out.println("moment of inertia: " + momentOfInertia + "\n");
		//momentOfInertia = 1;
		this.width = r; //might need to change this
		TG.addChild(createShape(r, color, sides));
	}
	
	public Polygon(int vertices, float mass, Tuple2f position, Tuple2f velocity, float orientation, float angularVelocity, float extwidth, float ratio, Color3f color) {
		this(vertices, mass, position.x, position.y, velocity.x, velocity.y, orientation, angularVelocity, extwidth, ratio, color);
	}
	
	@Override
	public void clearCaches() {
		vertexCache = null;
		normalCache = null;
	}

	public Vector2f[] getVertices() {
		if (vertexCache == null) {
			vertexCache = new Vector2f[vertices.length / 2];
			for (int i = 0; i < vertices.length; i += 2) {
				float tmpX = vertices[i] * width/(10*ratio); //DIVIDE
				float tmpY = vertices[i+1] * width/(10*ratio); //THESE
				vertexCache[i/2] = new Vector2f();
				vertexCache[i/2].x = (float)(Math.cos(orientation) * tmpX - Math.sin(orientation) * tmpY) + position.x;
				vertexCache[i/2].y = (float)(Math.sin(orientation) * tmpX + Math.cos(orientation) * tmpY) + position.y;
			}
		}
		return vertexCache;
	}
	
	public Vector2f[] getNormals() {
		if (normalCache == null) {
			Vector2f[] vertices = getVertices();
			normalCache = new Vector2f[vertices.length];

			for (int i = 0; i < vertices.length; i++) {
				normalCache[i] = new Vector2f();
				normalCache[i].scaleAdd(-1, vertices[i], vertices[(i+1)%vertices.length]);
				normalCache[i].normalize();
				float tmp = normalCache[i].x;
				normalCache[i].x = normalCache[i].y;
				normalCache[i].y = -tmp;
			}
		}
		return normalCache;
	}
	
	private Node createShape(float width, Color3f color, int sides) {
		IndexedTriangleArray geometry = 
				new IndexedTriangleArray(sides, GeometryArray.COORDINATES, 3*(sides-2));
		
		Point3f[] triVerts = new Point3f[sides];
		for (int i = 0; i < sides; i++)
			triVerts[i] = new Point3f(vertices[2*i], vertices[2*i+1], 0f);
		
		int[] triIndices = new int[3*(sides-2)];
		int triIndex = 0;
		for (int i = 1; i < sides-2+1; i++) {
			triIndices[triIndex++] = 0;
			triIndices[triIndex++] = i;
			triIndices[triIndex++] = i+1;
		}
		
		geometry.setCoordinates(0, triVerts);
		geometry.setCoordinateIndices(0, triIndices);
		
		PointArray centerOfMassGeometry = new PointArray(1, GeometryArray.COORDINATES);
		centerOfMassGeometry.setCoordinate(0, new Point3f(centerOfMass.x, centerOfMass.y, 0));
		
		BranchGroup root = new BranchGroup();
		if (color == null)
			color = new Color3f(Color.getHSBColor((float)Math.random(), 1, 1));
		Appearance appearance = new Appearance();
		appearance.setColoringAttributes(new ColoringAttributes(color, ColoringAttributes.FASTEST));
		PolygonAttributes polyAttr = new PolygonAttributes(PolygonAttributes.POLYGON_FILL, PolygonAttributes.CULL_NONE, 0);
		appearance.setPolygonAttributes(polyAttr);
		root.addChild(new Shape3D(geometry, appearance));
		
		appearance = new Appearance();
		appearance.setPointAttributes(new PointAttributes(4, true));
		root.addChild(new Shape3D(centerOfMassGeometry, appearance));
	
		return root;
	}
}
